/** LCD module **/
 
#include <p18cxxx.h>
#include <delays.h>
 
/** LCD display lines **/
#define L0_p1     0x80            /*Line 0 (upper line) with positions 1 to 16 */
#define L0_p2     0x81
#define L0_p3     0x82
#define L0_p4     0x83
#define L0_p5     0x84
#define L0_p6     0x85
#define L0_p7     0x86
#define L0_p8     0x87
#define L0_p9     0x88
#define L0_p10   0x89
#define L0_p11   0x8A
#define L0_p12   0x8B
#define L0_p13   0x8C
#define L0_p14   0x8D
#define L0_p15   0x8E
#define L0_p16   0x8F
 
#define L1_p1     0xC0        /*Line 1 (bottom line) with positions 1 to 16*/
#define L1_p2     0xC1
#define L1_p3     0xC2
#define L1_p4     0xC3
#define L1_p5     0xC4
#define L1_p6     0xC5
#define L1_p7     0xC6
#define L1_p8     0xC7
#define L1_p9     0xC8
#define L1_p10     0xC9
#define L1_p11     0xCA
#define L1_p12     0xCB
#define L1_p13     0xCC
#define L1_p14     0xCD
#define L1_p15     0xCE
#define L1_p16     0xCF
 
#define READ     1
#define WRITE    0
#define INSTR    0
#define DATA    1
 
 
/** LCD settings **/
#define FUNCTION_SET    0x38                 /** 8 bit bus, 2 lines **/
#define DISPLAY_OFF     0x08
#define DISPLAY_ON      0x0F
#define CLEAR_DISPLAY   0x01
#define ENTRY_MODE      0x06                 /** Increment mode, Entire Shift on**/
 
/** Delay values **/
#define POWER_DELAY   3800
#define FUNCTION_DELAY 5
#define DISPLAY_DELAY  5
#define CLEAR_DELAY   192
 
/** PSP pins **/
#define LCD_DATA    PORTD
#define LCD_D_DIR    TRISD
#define LCD_RS        PORTEbits.RE0           /** LCD Register Select control line **/
#define    LCD_RS_DIR    TRISEbits.TRISE0
#define LCD_RW        PORTEbits.RE1           /** LCD Read/Write control line **/
#define    LCD_RW_DIR    TRISEbits.TRISE1
#define LCD_E        PORTEbits.RE2           /** LCD Enable control line **/
#define    LCD_E_DIR    TRISEbits.TRISE2
 
 
/** Variables **/
int timer = 0;
 
/** Test Messages **/
rom char *message = "Cassia Scales";
 
/** Prototypes **/
void Initialise_LCD (void);
//void delay (unsigned int delayValue);
void Instruction_LCD(unsigned char value);
void BF_LCD(void);
unsigned char get_DDRAM (void);
void putchar_LCD (unsigned char cval);
void send_LCD (unsigned char dispval);
void string_LCD(rom char *pointer);
 
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     Start_LCD
*
*           Description:  Function that sets PORTD as input and PORTE as output. It then calls the initialisation of the LCD.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    "Main"
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void main (void)
{
    /** Initialise Parallel Slave Port **/
    TRISE = 0b00000000;                      /** PSPMODE configuration for PORTD and PORTE **/
    TRISD = 0x00;
    ADCON1 = 0b00000110;
 
    /** Delay function **/
    T1CON = 0b10110001;                      /** Fosc/4, 1:8 prescale value, Timer1 On **/
    CCP1CON = 0b00000010;                    /** Compare mode, toggle output on match (CCP1IF bit set)**/
    Initialise_LCD();
 
    Instruction_LCD(L0_p1);                     /** set cursor to column 1 row 1 **/
    Instruction_LCD(CLEAR_DISPLAY);          /** clear display and move cursor to home **/
    string_LCD(message);
    Instruction_LCD(L1_p1);                  /** set cursor to column 1 row 2 **/
 
    while(1);
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     Initialise_LCD
*
*           Description:   Function that initialises the LCD by instruction to an 8-bit interface mode.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void Initialise_LCD (void)
{
    PORTD = 0;
    LCD_E_DIR = 0;
    LCD_RS_DIR = 0;
    LCD_RW_DIR = 0;
 
    Delay1KTCYx(120);
    Instruction_LCD(FUNCTION_SET);           /** 8 bit interface, 2-lines **/
    Delay10TCYx(16);
    Instruction_LCD(DISPLAY_ON);             /** display, cursor and blink on **/
    Delay10TCYx(16);
    Instruction_LCD(CLEAR_DISPLAY);          /** Clear the display and return cursor home **/
    Delay100TCYx(62);
    Instruction_LCD(ENTRY_MODE);             /** Entry Mode Sets: Direction (right) of next character entry and shifts the display so that the cursor appears stationary **/
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     delay
*
*           Description:  Function that generates a delay time based on a 4MHz crystal and a prescale of 1:8.
*
*
*           Parameters:   delayValue
*
*           Return value: N/A
*
*           Behaviour:    Timer Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
//void delay (unsigned int delayValue)
//{
//    unsigned int tmrhi = TMR1H *256;         /** Shift to the left **/
//    unsigned int tmrlo = TMR1L & 0x00FF;
//    timer = tmrhi + tmrlo;                   /** Holds the TMR1 LSB and HSB into a 16 bit Timer "register" **/
//
//    CCPR1 = timer + delayValue;              /** The compare register contains the existing time plus a delay value based on the requires time**/
//
//    PIR1bits.CCP1IF = 0;
//    while(!PIR1bits.CCP1IF);
//}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     Instruction_LCD
*
*           Description:  Function that sends an instruction to the LCD.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void Instruction_LCD(unsigned char value)
{
  BF_LCD();                                /** check through Busy Flag that the LCD is ready to go **/
  LCD_RS = INSTR;                           /** selects Instruction register (IR) **/
  LCD_RW = WRITE;                           /** Sets write mode **/
  LCD_E = 1;                               /** Enable signal **/
  LCD_DATA = value;                           /** send out the command **/
  Nop();
  LCD_E = 0;                                /** complete an external write cycle **/
}
 
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     BF_LCD
*
*           Description:  Function that detects the LCD Busy Flag (BF)before executing the next instrunction.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
void BF_LCD(void)
{
     char check_bf;
    LCD_D_DIR = 0xFF;                    /** configure LCD data bus for input **/
    //check_bf = 0x80;
    while (check_bf)
    {
        LCD_RS = INSTR;                     /** Set LCD for instruction mode (IR) **/
        LCD_RW = READ;                     /** Set to read busy flag **/
        LCD_E = 1;                         /** Enable signal **/
        check_bf = LCD_DATA;            /** Read busy flag + DDram address **/
        LCD_E     = 0;                     /** complete a read cycle **/
        check_bf = check_bf & 0x80;     /** check Busy Flag, Busy = 1. DBit7 used for Busy Flag output **/
        }
    LCD_D_DIR     = 0x00;                 /** configure LCD data bus for output **/
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     get_DDRAM
*
*           Description:  Function that checks the busy flag and reads the DDRAM value.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
unsigned char get_DDRAM (void)
{
    char temp;
    LCD_D_DIR = 0xFF;                  /** configure LCD data port for input **/
    LCD_RS = 0;                           /** select IR register **/
    LCD_RW = 1;                           /** setup to read busy flag **/
    LCD_E = 1;                            /** LCD E-line to high **/
    temp = LCD_DATA & 0x7F;            /** read DDRAM address + busy flag **/
 
    LCD_E = 0;                            /** LCD E-line to low **/
    return temp;
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     putchar_LCD
*
*           Description:  Function that sends character to send_LCD.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void putchar_LCD (unsigned char cval)
{
    unsigned char address;
    BF_LCD();                   /** Wait for LCD to be ready **/
    send_LCD(cval);
    BF_LCD();                   /** Wait until LCD internal operation is complete **/
    address = get_DDRAM();
     if (address == 0x13)
        {
            Instruction_LCD(0xC0);
            BF_LCD();
            send_LCD(cval);
           }
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     send_LCD
*
*           Description:  Function that writes a character to LCD.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void send_LCD (unsigned char dispval)
{
    LCD_RS = 1;                 /** Set LCD in data mode **/
    LCD_RW =0;                  /** Set LCD in write mode **/
    LCD_E = 1;                  /** LCD E-line High **/
    LCD_DATA = dispval;         /** Send data to LCD **/
    LCD_E = 0;                  /** LCD E-line to Low **/
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------
*
*           Function:     string_LCD
*
*           Description:  Function that outputs a string stored into the LCD.
*
*
*           Parameters:   N/A
*
*           Return value: N/A
*
*           Behaviour:    Subfunction
*
*----------------------------------------------------------------------------------------------------------------------------------------------------*/
 
void string_LCD(rom char *pointer)
{
    while (*pointer)
    {
        putchar_LCD(*pointer);
        pointer++;
    }
}